import 'package:inmotion_protocol/lorin/bean/common/bms_info.dart';
import 'dart:typed_data';
import 'package:binary/binary.dart';
import 'package:inmotion_protocol/common/product_model.dart';
import 'package:inmotion_protocol/common/product_version.dart';
import 'package:inmotion_protocol/lorin/bean/common/date.dart';
import 'package:inmotion_protocol/util/byte_util.dart';

class P6BMSAllRealTimeInfo extends BMSAllRealTimeInfo {
  P6BMSAllRealTimeInfo(ProductModel model, VersionWrapper version)
      : super(model, version, true) {
    generalInfo = P6BMSGeneralInfo(model, version);
    state = BMSState(model, version);
    warning = P6BMSWarning(model, version);
    protection = P6BMSProtection(model, version);
    error = P6BMSError(model, version);
  }

  @override
  P6BMSGeneralInfo get generalInfo => super.generalInfo as P6BMSGeneralInfo;

  @override
  P6BMSWarning get warning => super.warning as P6BMSWarning;

  @override
  P6BMSProtection get protection => super.protection as P6BMSProtection;

  @override
  P6BMSError get error => super.error as P6BMSError;

  @override
  void initCompact() {
    compact = _DefaultP6BMSAllRealTimeInfo();
  }

}

class _DefaultP6BMSAllRealTimeInfo extends DefaultBMSAllRealTimeInfo<P6BMSAllRealTimeInfo> {
  @override
  void fromBytes(
      P6BMSAllRealTimeInfo output, Uint8ClampedList bytes, int offset) {
    output.format = ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;

    output.datetime = Datetime.fromBytes(bytes, offset: offset);
    offset += Datetime.length;

    output.generalInfo.fromBytes(bytes, offset);
    offset += output.generalInfo.length();

    output.state.fromBytes(bytes, offset);
    offset += output.state.length();

    output.warning.fromBytes(bytes, offset);
    offset += output.warning.length();

    output.protection.fromBytes(bytes, offset);
    offset += output.protection.length();

    output.error.fromBytes(bytes, offset);
    offset += output.error.length();
  }

  @override
  int length() => 58;
}

class P6BMSCellsVoltage extends BMSCellsVoltage {
  P6BMSCellsVoltage(super.apiVersion, super.version);

  @override
  int batteryCount() {
    return 56;
  }
}

class P6BMSGeneralInfo extends BMSGeneralInfo {
  P6BMSGeneralInfo(super.model, super.version);

  /// 当前电池允许的持续放电的电流
  Uint16 currentAllowedDischargeCurrent = Uint16.zero;

  @override
  void initCompact() {
    compact = _DefaultP6BMSGeneralInfoCompact();
    _setCellTempSensorCount(12);
  }

  @override
  int cellTempSensorCount() => 12;

  void _setCellTempSensorCount(int count) {
    cellsTemp = Int8List(count);
  }
}

class _DefaultP6BMSGeneralInfoCompact
    extends DefaultBMSGeneralInfoCompact<P6BMSGeneralInfo> {
  @override
  void fromBytes(P6BMSGeneralInfo output, Uint8ClampedList bytes, int offset) {
    output.voltage = ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;
    output.chargeCurrent = ByteUtil.bytes2Int16Le(bytes, offset);
    offset += 2;
    output.dischargeCurrent = ByteUtil.bytes2Int16Le(bytes, offset);
    offset += 2;
    output.fullCapacity = ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;
    output.remainCapacity = ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;
    output.fullChargeCycles = ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;
    output.maxCellVoltage = ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;
    output.minCellVoltage = ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;
    output.currentAllowedDischargeCurrent = ByteUtil.bytes2Uint16Le(bytes, offset);
    offset += 2;

    output.chargeMosTemp = ByteUtil.toInt8(ByteUtil.toInt8Int(bytes[offset]) + 80);
    offset++;
    output.dischargeMosTemp = ByteUtil.toInt8(ByteUtil.toInt8Int(bytes[offset]) + 80);
    offset++;
    output.boardTemp1 = ByteUtil.toInt8(ByteUtil.toInt8Int(bytes[offset]) + 80);
    offset++;
    output.boardTemp2 = ByteUtil.toInt8(ByteUtil.toInt8Int(bytes[offset]) + 80);
    offset++;
    for (var i = 0; i < output.cellsTemp.length; i++) {
      output.cellsTemp[i] =
          ByteUtil.toInt8(ByteUtil.toInt8Int(bytes[offset + i]) + 80).value;
    }
    offset += output.cellsTemp.length;

    output.relativeHumidity = ByteUtil.toUint8(bytes[offset]);
    offset++;

    // 保留1byte
    offset++;

    output.powerOffCountdown = ByteUtil.bytes2Uint16Le(bytes, offset);

    // 剩余2byte保留
  }

  @override
  int length() => 40;
}

class P6BMSWarning extends BMSWarning {
  /// 充电二极管过温告警
  Uint4 chargeDiodeOverTemp = Uint4.zero;

  /// 充电器电压错误告警
  Uint4 chargerVoltageError = Uint4.zero;

  /// 电芯温差过大警告(电芯温度超过18度，产生此警告)
  Uint4 cellTempDifferenceHighWarning = Uint4.zero;

  /// 充电BMS过温告警
  Uint4 chargeBMSOverTemp = Uint4.zero;

  /// 放电BMS过温告警
  Uint4 dischargeBMSOverTemp = Uint4.zero;

  /// 电芯压差过大告警
  Uint4 cellVoltageDifferenceHighWarning = Uint4.zero;

  /// 电池内部通讯告警
  Uint4 batteryCommunicationWarning = Uint4.zero;

  P6BMSWarning(super.model, super.version);

  @override
  void initCompact() {
    compact = _DefaultP6BMSWarningCompact();
  }

  @override
  String toString() {
    return 'P6BMSWarning{chargeDiodeOverTemp: $chargeDiodeOverTemp, chargerVoltageError: $chargerVoltageError, cellTempDifferenceHighWarning: $cellTempDifferenceHighWarning, ${super.toString()}}';
  }
}

class _DefaultP6BMSWarningCompact
    extends DefaultBMSWarningCompact<P6BMSWarning> {
  @override
  void fromBytes(P6BMSWarning output, Uint8ClampedList bytes, int offset) {
    output.lowSoc = ByteUtil.bitValue(bytes[offset], 0, 1);
    output.packOverCharge = ByteUtil.bitValue(bytes[offset], 1, 1);
    output.packOverDischarge = ByteUtil.bitValue(bytes[offset], 2, 1);
    output.cellOverCharge = ByteUtil.bitValue(bytes[offset], 3, 1);
    output.cellOverDischarge = ByteUtil.bitValue(bytes[offset], 4, 1);
    output.chargeOverCurrent = ByteUtil.bitValue(bytes[offset], 5, 1);
    // output.chargeMosOverTemp = ByteUtil.bitValue(bytes[offset], 6, 1);
    output.chargeBMSOverTemp = ByteUtil.bitValue(bytes[offset], 6, 1);
    output.chargeCellOverTemp = ByteUtil.bitValue(bytes[offset], 7, 1);
    offset++;

    output.chargeCellLowTemp = ByteUtil.bitValue(bytes[offset], 0, 1);
    output.dischargeOverCurrent = ByteUtil.bitValue(bytes[offset], 1, 1);
    // output.dischargeMosOverTemp = ByteUtil.bitValue(bytes[offset], 2, 1);
    output.dischargeBMSOverTemp = ByteUtil.bitValue(bytes[offset], 2, 1);
    output.dischargeCellOverTemp = ByteUtil.bitValue(bytes[offset], 3, 1);
    output.dischargeCellLowTemp = ByteUtil.bitValue(bytes[offset], 4, 1);
    output.overHumidity = ByteUtil.bitValue(bytes[offset], 5, 1);
    output.chargeDiodeOverTemp = ByteUtil.bitValue(bytes[offset], 6, 1);
    output.chargerVoltageError = ByteUtil.bitValue(bytes[offset], 7, 1);
    offset++;
    output.cellTempDifferenceHighWarning = ByteUtil.bitValue(bytes[offset], 0, 1);
    output.cellVoltageDifferenceHighWarning = ByteUtil.bitValue(bytes[offset], 1, 1);
    output.batteryCommunicationWarning = ByteUtil.bitValue(bytes[offset], 2, 1);
  }
}

class P6BMSProtection extends BMSProtection {
  P6BMSProtection(super.model, super.version);

  /// 充电BMS过温保护
  Uint4 chargeBMSOverTempProtection = Uint4.zero;

  /// 放电BMS过温保护
  Uint4 dischargeBMSOverTempProtection = Uint4.zero;

  /// 二级过充保护
  Uint4 chargeLock = Uint4.zero;

  /// 预充失败故障
  Uint4 preChargeFail = Uint4.zero;

  /// 放电保持标志
  Uint4 dischargeHold = Uint4.zero;

  @override
  void initCompact() {
    compact = _DefaultP6BMSProtectionCompact();
  }

  @override
  String toString() {
    return 'P6BMSProtection{chargeBMSOverTempProtection: $chargeBMSOverTempProtection, dischargeBMSOverTempProtection: $dischargeBMSOverTempProtection, chargeLock: $chargeLock, preChargeFail: $preChargeFail, dischargeHold: $dischargeHold, ${super.toString()}}';
  }

}

class _DefaultP6BMSProtectionCompact
    extends DefaultBMSProtectionCompact<P6BMSProtection> {
  @override
  void fromBytes(P6BMSProtection output, Uint8ClampedList bytes, int offset) {
    output.shortCircuit = ByteUtil.bitValue(bytes[offset], 0, 1);
    output.packOverCharge = ByteUtil.bitValue(bytes[offset], 1, 1);
    output.packOverDischarge = ByteUtil.bitValue(bytes[offset], 2, 1);
    output.cellOverCharge = ByteUtil.bitValue(bytes[offset], 3, 1);
    output.cellOverDischarge = ByteUtil.bitValue(bytes[offset], 4, 1);
    output.chargeOverCurrent = ByteUtil.bitValue(bytes[offset], 5, 1);
    output.chargeBMSOverTempProtection = ByteUtil.bitValue(bytes[offset], 6, 1);
    output.chargeCellOverTemp = ByteUtil.bitValue(bytes[offset], 7, 1);

    offset++;

    output.chargeCellLowTemp = ByteUtil.bitValue(bytes[offset], 0, 1);
    output.dischargeOverCurrent = ByteUtil.bitValue(bytes[offset], 1, 1);
    output.dischargeBMSOverTempProtection = ByteUtil.bitValue(bytes[offset], 2, 1);
    output.dischargeCellOverTemp = ByteUtil.bitValue(bytes[offset], 3, 1);
    output.dischargeCellLowTemp = ByteUtil.bitValue(bytes[offset], 4, 1);
    output.overHumidityTemp = ByteUtil.bitValue(bytes[offset], 5, 1);
    output.associatedCharge = ByteUtil.bitValue(bytes[offset], 6, 1);
    output.associatedDischarge = ByteUtil.bitValue(bytes[offset], 7, 1);
    offset++;
    output.chargeLock = ByteUtil.bitValue(bytes[offset], 0, 1);
    output.preChargeFail = ByteUtil.bitValue(bytes[offset], 1, 1);
    output.dischargeHold = ByteUtil.bitValue(bytes[offset], 2, 1);
  }
}

class P6BMSError extends BMSError {
  P6BMSError(super.model, super.version);

  /// 绝缘故障
  Uint4 insulation = Uint4.zero;

  /// 放电继电器无法闭合
  Uint4 dischargeRelayCannotClose = Uint4.zero;

  /// 放电继电器粘连
  Uint4 dischargeRelayCannotOpen = Uint4.zero;

  /// 充电继电器无法闭合
  Uint4 chargeRelayCannotClose = Uint4.zero;

  /// 充电继电器粘连
  Uint4 chargeRelayCannotOpen = Uint4.zero;

  @override
  void initCompact() {
    compact = _DefaultP6BMSErrorCompact();
  }

  @override
  String toString() {
    return 'P6BMSError{insulation: $insulation, dischargeRelayCannotClose: $dischargeRelayCannotClose, dischargeRelayCannotOpen: $dischargeRelayCannotOpen, chargeRelayCannotClose: $chargeRelayCannotClose, chargeRelayCannotOpen: $chargeRelayCannotOpen, ${super.toString()}}';
  }

}

class _DefaultP6BMSErrorCompact extends DefaultBMSErrorCompact<P6BMSError> {
  @override
  void fromBytes(P6BMSError output, Uint8ClampedList bytes, int offset) {
    super.fromBytes(output, bytes, offset);
    offset += 1;
    output.insulation = ByteUtil.bitValue(bytes[offset], 2, 1);
    output.dischargeRelayCannotClose = ByteUtil.bitValue(bytes[offset], 3, 1);
    output.dischargeRelayCannotOpen = ByteUtil.bitValue(bytes[offset], 4, 1);
    output.chargeRelayCannotClose = ByteUtil.bitValue(bytes[offset], 5, 1);
    output.chargeRelayCannotOpen = ByteUtil.bitValue(bytes[offset], 6, 1);
  }
}
